//#define USE_DUNGEONBUDDY_DLL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonBehaviors.Actions;
using Styx;
using Styx.CommonBot;
using Styx.Patchables;
using Styx.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.TreeSharp;
using Action = Styx.TreeSharp.Action;
#if USE_DUNGEONBUDDY_DLL
using Bots.DungeonBuddyDll;
using Bots.DungeonBuddyDll.Profiles;
using Bots.DungeonBuddyDll.Attributes;
using Bots.DungeonBuddyDll.Helpers;

namespace Bots.DungeonBuddyDll.Dungeon_Scripts.Classic
#else
    using Bots.DungeonBuddy.Profiles;
    using Bots.DungeonBuddy.Attributes;
    using Bots.DungeonBuddy.Helpers;
namespace Bots.DungeonBuddy.Dungeon_Scripts.Classic
#endif
{
    #region Normal Difficulty

    public class ScarletHalls : Dungeon
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 163; }
        }

        public override WoWPoint Entrance
        {
            get { return new WoWPoint(2864.618, -823.2136, 160.3323); }
        }

        public override WoWPoint ExitLocation
        {
            get { return new WoWPoint(820.4927, 614.8466, 13.50341); }
        }

        public override void RemoveTargetsFilter(List<WoWObject> units)
        {
            units.RemoveAll(
                ret =>
                    {
                        var unit = ret as WoWUnit;
                        if (unit != null)
                        {
                            if (unit.Entry == ObedientHound && unit.Location.DistanceSqr(_houndMasterRoomCenter) > 13*13)
                                return true;
                            // ignore Commander Lindon or the master archers if they don't have a target and I don't have an archery target on.
                            if ((unit.Entry == CommanderLindonId || unit.Entry == MasterArcher) && StyxWoW.Me.IsTank() && !StyxWoW.Me.HasAura("Heroic Defense") &&
                                !unit.GotTarget)
                                return true;

                            if (unit.Entry == ScarletGuardianId || unit.Entry == SergeantVerdoneId)
                                return true;

                            if (unit.Entry == ScarletDefender)
                            {
                                if (StyxWoW.Me.IsMelee() && unit.ZDiff > 3)
                                    return true;

                                bool harlanIsSpinning = _armsmasterHarlan != null && _armsmasterHarlan.IsValid &&
                                                        (_armsmasterHarlan.HasAura("Blades of Light") || _armsmasterHarlan.CastingSpellId == BladesOfLightSpellId);

                                if (harlanIsSpinning && (StyxWoW.Me.Z > 2 || _armsmasterHarlan.ZDiff < 5))
                                    return true;

                                if (!harlanIsSpinning)
                                    return true;

                                //// ignore them if they're not in melee range while waiting at top of stairs.
                                //if (StyxWoW.Me.Z > 4 && unit.Distance > 4.5)
                                //    return true;
                                //if (StyxWoW.Me.Z < 2 && unit.Z > 2 || unit.Distance > 8)
                                //    return true;
                            }
                            if (unit.Entry == ArmsmasterHarlan && (unit.HasAura("Blades of Light") || unit.CastingSpellId == BladesOfLightSpellId) && !StyxWoW.Me.IsHealer())
                                return true;
                        }
                        return false;
                    });
        }

        public override void IncludeTargetsFilter(List<WoWObject> incomingunits, HashSet<WoWObject> outgoingunits)
        {
            foreach (var obj in incomingunits)
            {
                var unit = obj as WoWUnit;
                if (unit != null)
                {
                    // in some CCs the healer won't heal unless there are units in the target list.
                    if (unit.Entry == CommanderLindonId && StyxWoW.Me.IsHealer())
                        outgoingunits.Add(unit);

                    if (unit.Entry == ScarletCannoneer)
                    {
                        if (Me.IsTank() && unit.Distance <= 40)
                            outgoingunits.Add(unit);
                        else
                        {
                            var tank = ScriptHelpers.Tank;
                            if (tank != null && tank.IsAlive && tank.CurrentTargetGuid == unit.Guid)
                                outgoingunits.Add(unit);
                        }
                    }
                }
            }
        }

        public override void WeighTargetsFilter(List<Targeting.TargetPriority> units)
        {
            foreach (var priority in units)
            {
                var unit = priority.Object as WoWUnit;
                if (unit != null)
                {
                    if (unit.Entry == ObedientHound && unit.Location.DistanceSqr(_houndMasterRoomCenter) <= 15*15)
                        priority.Score += 400;

                    if (unit.Entry == ScarletScholar && StyxWoW.Me.IsDps())
                        priority.Score += 400;

                    // if (unit.Entry == ScarletDefender && unit.HasAura("Unarmored") && unit.ZDiff < 2 && StyxWoW.Me.IsDps())
                    //      priority.Score += 500;
                }
            }
        }

        #endregion

        private const int LootSparklesAuraId = 113628;

        private const uint CommanderLindonId = 59191;
        private const uint MasterArcher = 59175;
        private const uint ObedientHound = 59309;
        private const uint ArmsmasterHarlan = 58632;
        private const uint ScarletScholar = 59372;
        private const uint ScarletCannoneer = 59293;
        private const uint ScarletDefender = 58998;
        private const int BladesOfLightSpellId = 111216;
        private const uint ScarletGuardianId = 59299;
        private const uint SergeantVerdoneId = 59302;

        private readonly WoWPoint _houndMasterRoomCenter = new WoWPoint(1009.557, 513.6875, 12.9061);
        private WoWUnit _armsmasterHarlan;

        private LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        private WoWUnit ReinforcedArcheryTarget
        {
            get
            {
                return
                    ObjectManager.GetObjectsOfType<WoWUnit>()
                                 .Where(u => u.Entry == 59163 && u.DistanceSqr <= 25*25 && u.HasAura(LootSparklesAuraId))
                                 .OrderBy(u => u.DistanceSqr)
                                 .FirstOrDefault();
            }
        }

        [EncounterHandler(0)]
        public Composite Root()
        {
            return new PrioritySelector();
        }

        [EncounterHandler(64738, "Hooded Crusader", Mode = CallBehaviorMode.Proximity)]
        [EncounterHandler(64764, "Hooded Crusader", Mode = CallBehaviorMode.Proximity)]
        public Composite HoodedCrusaderEncounter()
        {
            WoWUnit unit = null;
            return new PrioritySelector(
                ctx => unit = ctx as WoWUnit,
                // pickup quests.
                new Decorator(ctx => unit.QuestGiverStatus == QuestGiverStatus.Available, ScriptHelpers.CreatePickupQuest(() => unit)),
                new Decorator(ctx => unit.QuestGiverStatus == QuestGiverStatus.TurnIn, ScriptHelpers.CreateTurninQuest(() => unit)));
        }

        [EncounterHandler(59191, "Commander Lindon", BossRange = 100, Mode = CallBehaviorMode.Proximity)]
        public Composite CommanderLindonEncounter()
        {
            const uint explodingShotStalker = 59683;

            WoWUnit shield = null;
            AddAvoidObject(ctx => !StyxWoW.Me.HasAura("Heroic Defense") && StyxWoW.Me.IsTank() || !StyxWoW.Me.IsTank(), 7, explodingShotStalker);

            return new PrioritySelector(
                new Decorator(ctx => StyxWoW.Me.HasAura("Heroic Defense"), new Helpers.Action<WoWUnit>(boss => Navigator.MoveTo(boss.Location))),
                // pickup a shield 
                new Decorator(
                    ctx =>
                    !StyxWoW.Me.HasAura("Heroic Defense") && !StyxWoW.Me.IsHealer() && Targeting.Instance.IsEmpty() &&
                    (StyxWoW.Me.IsTank() || ScriptHelpers.Tank.HasAura("Heroic Defense")) && // cache the ReinforcedArcheryTarget 
                    (shield = ReinforcedArcheryTarget) != null,
                    new PrioritySelector(
                        new Decorator(ctx => shield.WithinInteractRange, new Action(ctx => shield.Interact())),
                        new Decorator(ctx => !shield.WithinInteractRange, new Action(ctx => Navigator.MoveTo(shield.Location))))));
        }


        [EncounterHandler(59303, "Houndmaster Braun")]
        public Composite HoundmasterBraunBehavior()
        {
            WoWUnit boss = null;
            AddAvoidObject(
                ctx => true,
                () => _houndMasterRoomCenter,
                10,
                3,
                u => u is WoWPlayer && ((WoWPlayer) u).HasAura("Piercing Throw") && !u.IsMe,
                o =>
                    {
                        var loc = o.Location;
                        return StyxWoW.Me.Location.GetNearestPointOnSegment(loc, boss.Location);
                    });

            AddAvoidObject(ctx => true, 8, SergeantVerdoneId);

            return new PrioritySelector(
                ctx => boss = ctx as WoWUnit,
                new Decorator(ctx => Me.Location.Distance(_houndMasterRoomCenter) > 10, new Action(ctx => Navigator.MoveTo(_houndMasterRoomCenter))),
                new Decorator(
                    ctx => !Targeting.Instance.IsEmpty() && Targeting.Instance.FirstUnit.CurrentTargetGuid == Me.Guid,
                    ScriptHelpers.CreateTankUnitAtLocation(() => _houndMasterRoomCenter, 10)));
        }

        [EncounterHandler(58632, "Armsmaster Harlan")]
        public Composite ArmsmasterHarlanBehavior()
        {
            var roomCenter = new WoWPoint(1206.436, 443.9618, 0.9878645);
            var leftMovetoLoc = new WoWPoint(1204.795, 457.1326, 1.071114);
            var rightMovetoLoc = new WoWPoint(1204.293, 430.942, 1.072392);
            var bladesOfLightMoveToLoc = new WoWPoint(1216.27, 444.024, 0.9885067);
            var bladesOfLightMoveToTopLoc = new WoWPoint(1218.714, 443.9204, 6.082577);


            bool isCastingBladesOfLight = false;

            return new PrioritySelector(
                ctx =>
                    {
                        _armsmasterHarlan = (WoWUnit) ctx;
                        isCastingBladesOfLight = _armsmasterHarlan.HasAura("Blades of Light") || _armsmasterHarlan.CastingSpellId == BladesOfLightSpellId;
                        return _armsmasterHarlan;
                    },
                // ScriptHelpers.CreateRunAwayFromBad(ctx => true, 8, u => u.Entry == ArmsmasterHarlan &&  u.ToUnit().CastingSpellId == BladesOfLightSpellId),
                // ScriptHelpers.GetBehindUnit(ctx => !isCastingBladesOfLight && !StyxWoW.Me.IsTank() && _armsmasterHarlan.IsSafelyFacing(StyxWoW.Me) && _armsmasterHarlan.Distance < 8, () => _armsmasterHarlan),

                ScriptHelpers.CreateAvoidUnitAnglesBehavior(
                    ctx => !StyxWoW.Me.IsTank() && !isCastingBladesOfLight && StyxWoW.Me.Z < 2, () => _armsmasterHarlan, new ScriptHelpers.AngleSpan(0, 160)),
                new Decorator(ctx => StyxWoW.Me.IsTank() && !isCastingBladesOfLight, ScriptHelpers.CreateTankFaceAwayGroupUnit(8)),
                // boss ports to here when spinning around.
                //ScriptHelpers.CreateRunAwayFromLocation(ctx => !boss.HasAura("Blades of Light") && boss.CastingSpellId != BladesOfLightSpellId, 8, arg => roomCenter),

                new Decorator(
                    ctx => _armsmasterHarlan.HasAura("Berserker Rage") && _armsmasterHarlan.Auras["Berserker Rage"].StackCount >= 4,
                    ScriptHelpers.CreateDispellEnemy("Berserker Rage", ScriptHelpers.EnemyDispellType.Enrage, () => _armsmasterHarlan)),
                // dodge blades of light
                new Decorator(
                    ctx => isCastingBladesOfLight,
                    new PrioritySelector(
                        /*
                new Decorator(ctx => Me.Location.Distance2D(bladesOfLightMoveToLoc) > Navigator.PathPrecision, new Action(ctx => Navigator.MoveTo(bladesOfLightMoveToLoc))),
                new Decorator(ctx => Me.Location.Distance2D(bladesOfLightMoveToLoc) > 1, new Action(ctx => Navigator.PlayerMover.MoveTowards(bladesOfLightMoveToLoc))),
                new Decorator(ctx => ScriptHelpers.MovementEnabled, new Action(ctx => ScriptHelpers.DisableMovement(() => isCastingBladesOfLight))) 
                 */

                        new ActionSetActivity("Running from Blades Of Light"),
                        new Decorator(
                            ctx => _armsmasterHarlan.Location.Distance(roomCenter) <= 2 && StyxWoW.Me.Location.Distance(bladesOfLightMoveToTopLoc) > 3,
                            new Action(ctx => Navigator.MoveTo(bladesOfLightMoveToTopLoc))),
                        new Decorator(
                            ctx => _armsmasterHarlan.Location.Distance(roomCenter) > 2 && StyxWoW.Me.Location.Distance(roomCenter) > 3,
                            new Action(ctx => Navigator.PlayerMover.MoveTowards(roomCenter))),
                        new Decorator(ctx => StyxWoW.Me.IsTank() && Targeting.Instance.IsEmpty(), new ActionAlwaysSucceed()))),
                // move off stairs.
                new Decorator(
                    ctx => StyxWoW.Me.Z >= 2f && !isCastingBladesOfLight,
                    new PrioritySelector(
                        new ActionSetActivity("Moving off stairs."),
                        new Action(
                            ctx =>
                            Navigator.MoveTo(StyxWoW.Me.Location.DistanceSqr(leftMovetoLoc) < StyxWoW.Me.Location.DistanceSqr(rightMovetoLoc) ? leftMovetoLoc : rightMovetoLoc)))));
        }

        [EncounterHandler(59150, "Flameweaver Koegler")]
        public Composite FlameweaverKoeglerBehavior()
        {
            var flamebreathMoveLoc = new WoWPoint(1300.889, 545.713, 12.80321);
            const int dragonsBreath = 113641;
            const int pyroBlastId = 113690;
            const uint BookCase = 59155;
            WoWUnit boss = null;
            AddAvoidObject(ctx => true, () => flamebreathMoveLoc, 10, 15, u => u.Entry == BookCase && ((WoWUnit) u).HasAura("Burning Books"));

            return new PrioritySelector(
                ctx => boss = ctx as WoWUnit,
                ScriptHelpers.GetBehindUnit(ctx => boss.CastingSpellId == dragonsBreath && !StyxWoW.Me.IsCasting, () => boss),
                ScriptHelpers.CreateDispellEnemy("Quickened Mind", ScriptHelpers.EnemyDispellType.Magic, () => boss),
                ScriptHelpers.CreateInterruptCast(() => boss, pyroBlastId));
        }
    }

    #endregion

    #region Heroic Difficulty

    public class ScarletHallsHeroic : ScarletHalls
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 473; }
        }

        #endregion
    }

    #endregion

}